package language.advanced;

import lombok.AllArgsConstructor;
import lombok.Data;
import org.junit.Test;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toList;
import static java.util.stream.IntStream.range;

public class streamTest {

//    @Test // Shape和ShapeChild必须满足继承关系才能使用这段代码
//    public void stream() {
//        Stream.of(Stream.generate(Shape::new).limit(2),
//                Stream.generate(ShapeChild::new).limit(2))
//                .flatMap(c -> c) // flatten into one stream
//                .peek(Shape::rotate)
//                .forEach(s -> s.resize(7));
//    }

    //在stream中处理受检异常，需要重写一个不会抛出异常的方法
    @Test
    public void streamHandleException() {
        List<String> address = Arrays.asList("1", "2", "3");
        String collect = address.stream()
                .map(this::encodeString)
                .collect(Collectors.joining(","));
        System.out.println(collect);


        //public static<T> Stream<T> generate(Supplier<T> s)
        // generate函数接受最简单的形式 () -> "abc" 返回一个固定的字符串
        String collect1 = Stream.generate(() -> "abc")
                .limit(10)
                .collect(Collectors.joining(" "));
        System.out.println(collect1);
    }

    private String encodeString(String s) {
        try {
            return URLEncoder.encode(s, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return s;
    }

    @Test
    public void intStream() {
        //Rang构造IntStream
        range(1, 4).forEach(System.out::println); //1 2 3

        //生成随机数流
        Random rand = new Random(47);
        rand.ints(); // 还有rand.longs()、rand.doubles()
        rand.ints(2); //控制流生成的大小
        rand.ints(10, 20); //控制上限和下限
        rand.ints(3, 3, 9); //控制流的大小和界限

        //数值流独有的终结操作
        OptionalDouble average = range(1, 9).average();
        OptionalInt min = range(1, 9).min();// min和max的返回类型为Optional
        int max = range(1, 9).max().getAsInt();// 数值流的min和max操作无需Comparator
        int sum = range(1, 9).sum();
        IntSummaryStatistics intSummaryStatistics = range(1, 9).summaryStatistics();
    }


    @Test
    public void builder() {
        Stream.Builder<String> builder = Stream.builder();
        builder.add("a");
        builder.add("b");
        builder.add("c");
        //        Files.lines(Paths.get(filePath))
        //                .skip(1) // 略过开头的注释行
        //                .forEach(line -> {
        //                    for (String w : line.split("[ .?,]+"))
        //                        builder.add(w);
        //                });
        builder.build().limit(2).forEach(System.out::println);
    }

    @Test
    public void unlimit() {
        Stream.generate(() -> "a").limit(3).forEach(System.out::println);

        Stream.iterate("a", b -> b + "b").limit(3).forEach(System.out::println);

        //Fibonacci数列
        AtomicInteger x = new AtomicInteger(1);
        Stream.iterate(0, i -> {
            int result = x.get() + i;
            x.set(i);
            return result;
        }).limit(10) // 然后取 10 个
                .forEach(System.out::println);
    }


    @Test
    public void intermediate() {
        // sorted
        List<Integer> integers = Arrays.asList(1, 8, 3, 4, 5);
        integers.stream().sorted(Comparator.comparingInt(x -> x)).forEach(System.out::println);
        // compare结果为负 排序： x前 y后
        // compare结果为正 排序： y前 x后

        // flatMap
        ArrayList<List<String>> lists = new ArrayList<>();
        List<String> strings = Arrays.asList("A", "B");
        List<String> strings1 = Arrays.asList("C", "D");
        lists.add(strings);
        lists.add(strings1);
        //[["A","B"],["C","D"]]
        lists.stream().flatMap(Collection::stream).forEach(System.out::println); //[A, B, C, D]

        List<String> strings2 = Arrays.asList("Hello", "World");
        strings2.stream()
                .flatMap(word -> Arrays.stream(word.split("")))
                .distinct()
                .forEach(System.out::println);
    }

    @Test //利用stream做分页操作
    public void streamPage() {
        int pageSize = 3;
        int pageNum = 2;
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
        //stream分页
        List<Integer> collect = numbers.stream()
                .skip((pageNum - 1) * pageSize)
                .limit(pageSize)
                .collect(toList());
        System.out.println(collect);
    }

    @Test
    public void terminate() {
        Stream<String> stream = Stream.of("a", "b", "c");
        //集合收集
        //收集collect到一个map
        Map<String, Integer> collect = stream.collect(Collectors.toMap(x -> x, x -> 1));
        System.out.println(collect);

        //collect三参数用法
        List<String> l = stream.collect(
                ArrayList::new,
                (a, b) -> a.add(b + "bddd"),
                ArrayList::addAll);
        System.out.println(l);


        //数组收集
//        Object[] obj = stream.toArray();
//        String[] strings = stream.toArray(String[]::new);
//        System.out.println(Arrays.toString(strings));

//         reduce 规约
        ArrayList<User> userList = new ArrayList<>();
        userList.add(new User("aa",17));
        userList.add(new User("bb",18));
        int result2 = userList.stream()
                // 将user对象的age取出来map为Bigdecimal
                .map(User::getAge)
                // 使用reduce()聚合函数,实现累加器
                .reduce(0, Integer::sum);
        System.out.println(result2);

        Integer integer = Stream.of(1, 2, 3)
                .min(Integer::compareTo).orElse(0);
    }
}

@Data
@AllArgsConstructor
class User {
    private String name;
    private int age;
}